﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DotNetCommon.Extensions;

namespace DotNetCommon.Data;

/// <summary>
/// 通用结果模型
/// </summary>
public class Result<T>
{
    /// <summary>
    /// 可以使用 <seealso cref="Result.NewInstance{T}"/> 代替
    /// </summary>
    public Result() { }

    /// <summary>
    /// 状态码,一般用来表示错误类别
    /// </summary>
    /// <remarks>
    /// 这里设置为 int? 而不是 int, 是为了在不使用code的时候, 序列化配置为忽略null值即可省略code
    /// </remarks>
    public int? Code { get; set; }

    /// <summary>
    /// 消息文本,一般用来做错误提示
    /// </summary>
    public string Message { get; set; }

    /// <summary>
    /// 扩展数据
    /// </summary>
    public object ExtData { get; set; }

    /// <summary>
    /// 执行成功或失败
    /// </summary>
    public bool Success { get; set; }

    /// <summary>
    /// 执行的结果数据
    /// </summary>
    public T Data { get; set; }

    /// <summary>
    /// 隐示转换
    /// </summary>
    public static implicit operator Result<T>(Result res)
    {
        if (res.Data is T t)
        {
            return new Result<T>()
            {
                Code = res.Code,
                Message = res.Message,
                ExtData = res.ExtData,
                Success = res.Success,
                Data = t
            };
        }
        else
        {
            T tmp = default;
            if (typeof(T).IsSimpleType())
            {
                try
                {
                    tmp = res.Data.To<T>();
                }
                catch { }
            }
            else
            {
                try
                {
                    tmp = (T)res.Data.Mapper(typeof(T));
                }
                catch { }
            }
            return new Result<T>()
            {
                Code = res.Code,
                Message = res.Message,
                ExtData = res.ExtData,
                Success = res.Success,
                Data = tmp
            };
        }

    }

    #region 设置数据
    /// <summary>
    /// 设置数据
    /// </summary>
    public Result<T> SetData(T data)
    {
        this.Data = data;
        return this;
    }

    /// <summary>
    /// 设置Code
    /// </summary>
    public Result<T> SetCode(int? code)
    {
        this.Code = code;
        return this;
    }

    /// <summary>
    /// 设置响应消息
    /// </summary>
    public Result<T> SetMessage(string message)
    {
        this.Message = message;
        return this;
    }

    /// <summary>
    /// 将响应标记成功
    /// </summary>
    public Result<T> SetSuccess()
    {
        this.Success = true;
        return this;
    }

    /// <summary>
    /// 将响应标记失败
    /// </summary>
    public Result<T> SetFail()
    {
        this.Success = false;
        return this;
    }

    /// <summary>
    /// 设置响应标记
    /// </summary>
    public Result<T> SetSuccessFlag(bool isSuccess)
    {
        this.Success = isSuccess;
        return this;
    }

    /// <summary>
    /// 设置扩展数据
    /// </summary>
    public Result<T> SetExtData(object extData)
    {
        this.ExtData = extData;
        return this;
    }
    #endregion
}

/// <summary>
/// 以object作为结果数据类别,提供静态快捷方法
/// </summary>
public class Result : Result<object>
{
    /// <summary>
    /// 可以使用 <seealso cref="Result.NewInstance"/> 代替
    /// </summary>
    public Result() { }

    #region 设置数据
    /// <summary>
    /// 设置数据
    /// </summary>
    public new Result SetData(object data)
    {
        this.Data = data;
        return this;
    }

    /// <summary>
    /// 设置Code
    /// </summary>
    public new Result SetCode(int? code)
    {
        this.Code = code;
        return this;
    }

    /// <summary>
    /// 设置响应消息
    /// </summary>
    public new Result SetMessage(string message)
    {
        this.Message = message;
        return this;
    }

    /// <summary>
    /// 将响应标记成功
    /// </summary>
    public new Result SetSuccess()
    {
        this.Success = true;
        return this;
    }

    /// <summary>
    /// 将响应标记失败
    /// </summary>
    public new Result SetFail()
    {
        this.Success = false;
        return this;
    }

    /// <summary>
    /// 设置响应标记
    /// </summary>
    public new Result SetSuccessFlag(bool isSuccess)
    {
        this.Success = isSuccess;
        return this;
    }

    /// <summary>
    /// 设置扩展数据
    /// </summary>
    public new Result SetExtData(object extData)
    {
        this.ExtData = extData;
        return this;
    }
    #endregion

    #region NewInstance
    /// <summary>
    /// 创建Result实例
    /// </summary>
    public static Result NewInstance() => new();

    /// <summary>
    /// 创建Result&lt;T>实例
    /// </summary>
    public static Result<T> NewInstance<T>() => new();
    #endregion

    /// <summary>
    /// 返回成功
    /// </summary>
    public static Result<T> Ok<T>(T value)
    {
        return new Result<T>()
        {
            Success = true,
            Data = value
        };
    }

    /// <summary>
    /// 返回成功,不需要附带模型数据
    /// </summary>
    public static Result Ok()
    {
        return new Result()
        {
            Success = true
        };
    }

    /// <summary>
    /// 返回分页模型数据
    /// </summary>
    public static Result<Page<T>> OkPage<T>(int totalCount, List<T> list)
        => OkPage((long)totalCount, list);

    /// <summary>
    /// 返回分页模型数据
    /// </summary>
    public static Result<Page<T>> OkPage<T>(long totalCount, List<T> list)
    {
        return new Result<Page<T>>()
        {
            Success = true,
            Data = new Page<T>()
            {
                TotalCount = totalCount,
                List = list
            }
        };
    }

    /// <summary>
    /// 返回失败结果
    /// </summary>
    public static Result NotOk(string message, int? code = 0, object data = null, object extData = null)
    {
        return new Result()
        {
            Success = false,
            Message = message,
            ExtData = extData,
            Code = code,
            Data = data
        };
    }

    /// <summary>
    /// 包裹程序段,捕捉程序段内的异常并使用Result模型封装
    /// </summary>
    /// <remarks>注意: 如果传入的委托是null, 则返回错误</remarks>
    public static Result<T> WrapReturn<T>(Func<T> func)
    {
        if (func == null) return NotOk($"参数: {nameof(func)} 不能为空");
        try
        {
            var t = func();
            return Ok(t);
        }
        catch (Exception ex)
        {
            return NotOk(ex?.Message);
        }
    }

    /// <summary>
    /// 包裹异步程序段,捕捉程序段内的异常并使用Result模型封装
    /// </summary>
    /// <remarks>注意: 如果传入的委托是null, 则返回错误</remarks>
    public static async Task<Result<T>> WrapReturnAsync<T>(Func<Task<T>> func)
    {
        if (func == null) return NotOk($"参数: {nameof(func)} 不能为空");
        try
        {
            var t = await func();
            return Ok(t);
        }
        catch (Exception ex)
        {
            return NotOk(ex?.Message);
        }
    }

    /// <summary>
    /// 包裹程序段,捕捉程序段内的异常并使用Result模型封装
    /// </summary>
    /// <remarks>注意: 如果传入的委托是null, 则返回错误</remarks>
    public static Result Wrap(Action action)
    {
        if (action == null) return NotOk($"参数: {nameof(action)} 不能为空");
        try
        {
            action();
            return Ok();
        }
        catch (Exception ex)
        {
            return NotOk(ex?.Message);
        }
    }

    /// <summary>
    /// 包裹异步程序段,捕捉程序段内的异常并使用Result模型封装
    /// </summary>
    /// <remarks>注意: 如果传入的委托是null, 则返回错误</remarks>
    public static async Task<Result> WrapAsync(Func<Task> action)
    {
        if (action == null) return NotOk($"参数: {nameof(action)} 不能为空");
        try
        {
            await action();
            return Ok();
        }
        catch (Exception ex)
        {
            return NotOk(ex?.Message);
        }
    }
}

/// <summary>
/// Result扩展类
/// </summary>
public static class ResultExtensions
{
    /// <summary>
    /// 解开Result模型, Result.Success为true则返回模型,否则抛出ResultException异常
    /// </summary>
    public static T UnWrap<T>(this Result<T> result)
    {
        if (result.Success) return result.Data;
        throw new ResultException(result.Message, result.Code);
    }

    /// <summary>
    /// 解开Result模型, Result.Success为true则返回模型,否则抛出ResultException异常
    /// </summary>
    public static object UnWrap(this Result result)
    {
        if (result.Success) return result.Data;
        throw new ResultException(result.Message, result.Code);
    }
}
